package 动态数组.栈.中缀表达式;

import 动态数组.栈.ArrayStack;

/**
 * 中缀表达式的计算，栈的应用
 * @author veneno
 */
public class InfixCalculator {
    public static void main(String[] args) {
        String expression = "(10+20/2*3)/2+8";
        try {
            System.out.println(expression+"="+evaluateExpression(expression));
        } catch (Exception e) {
            System.out.println("输入表达式错误！");
        }
    }

    private static int evaluateExpression(String expression) {
        //对表达式进行分割，获得正确的表达式,格式化表达式
        expression = format(expression);
        String[] tokens = expression.split("#");
        //定义存储数字和操作的栈
        ArrayStack<Character> operationStack = new ArrayStack<>();
        ArrayStack<Integer> numberStack = new ArrayStack<>();
        for (String token : tokens) {
            //过滤表达式中的空格
            if (token.length() == 0){
                continue;
            }
            //分别判断token是什么类型
            if (token.charAt(0) == '+' || token.charAt(0) == '-'){
                while(!operationStack.isEmpty() && operationStack.peek() != '('){
                    processAnOperation(operationStack,numberStack);
                }
                operationStack.push(token.charAt(0));
            }else if (token.charAt(0) == '*' || token.charAt(0) == '/'){
                while(!operationStack.isEmpty() && operationStack.peek() != '(' &&
                        (operationStack.peek() == '*' || operationStack.peek() == '/')){
                    processAnOperation(operationStack,numberStack);
                }
                operationStack.push(token.charAt(0));
            }else if (token.charAt(0) == '('){
                //'('直接添加
                operationStack.push('(');
            }else if(token.charAt(0) == ')'){
                while (operationStack.peek() != '('){
                    processAnOperation(operationStack,numberStack);
                }
                operationStack.pop();
            }else {
                //数字也直接添加
                numberStack.push(Integer.parseInt(token));
            }

        }
        while (!operationStack.isEmpty()){
            processAnOperation(operationStack,numberStack);
        }

        System.out.println(numberStack.size());
        System.out.println(numberStack);
        System.out.println(operationStack.size());
        if (numberStack.size() > 1){
            throw  new IllegalArgumentException();
        }
        return numberStack.pop();
    }

    private static void processAnOperation(ArrayStack<Character> operationStack, ArrayStack<Integer> numberStack) {
        char op = operationStack.pop();
        int num2 = numberStack.pop();
        int num1 = numberStack.pop();
        switch (op){
            case '+':
                numberStack.push(num1 + num2);
                break;
            case '-':
                numberStack.push(num1 - num2);
                break;
            case '*':
                numberStack.push(num1 * num2);
                break;
            case '/':
                numberStack.push(num1 / num2);
                break;
            default:
                break;
        }
    }

    public static String format(String expression){
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < expression.length(); i++) {
            //如果仅过滤数字的话，不会过滤如下情况："(10+20/2*3)(1+2)/2+8"，会使数字栈有两个数字bottom [40,9] top，
            //会将两个括号中的内容分别进行一个计算，因此要写全
            char c = expression.charAt(i);
            if (c == '(' || c == ')' || c == '+' || c == '-' || c == '*' || c == '/'){
                sb.append('#');
                sb.append(c);
                sb.append('#');
            }else {
                sb.append(c);
            }
        }
        return sb.toString();
    }
}
